package org.iabako.client.ui.form.business.payment;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.HTMLPanel;
import org.iabako.client.navigation.NavigationController;
import org.iabako.client.tools.IabakoAsyncCallback;
import org.iabako.client.tools.Messages;
import org.iabako.client.ui.form.AbstractForm;
import org.iabako.client.ui.form.business.sale.SalePaymentsForm;
import org.iabako.client.ui.layout.field.*;
import org.iabako.client.ui.layout.widget.dialogbox.IabakoDialogBox;
import org.iabako.client.ui.layout.widget.validation.ValidationMessage;
import org.iabako.client.user.AuthenticateUserProvider;
import org.iabako.shared.entity.business.AbstractEntity;
import org.iabako.shared.entity.business.Installment;
import org.iabako.shared.entity.business.Payment;
import org.iabako.shared.entity.enumeration.NotificationType;
import org.iabako.shared.entity.enumeration.PaymentMethod;
import org.iabako.shared.entity.enumeration.TrackingType;
import org.iabako.shared.iservice.business.InstallmentServiceAsync;
import org.iabako.shared.iservice.business.PaymentServiceAsync;
import org.iabako.shared.iservice.business.SaleServiceAsync;
import org.iabako.shared.tools.GenericTools;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * Created by jose on 08/09/14.
 */
public abstract class OnePaymentForm extends AbstractForm {

    interface MyUiBinder extends UiBinder<HTMLPanel, OnePaymentForm> {
    }

    protected MyUiBinder binderPaymentForm = GWT.create(MyUiBinder.class);

    protected final SaleServiceAsync saleServiceAsync = SaleServiceAsync.Util.getInstance();
    protected final PaymentServiceAsync paymentServiceAsync = PaymentServiceAsync.Util.getInstance();
    protected final InstallmentServiceAsync installmentServiceAsync = InstallmentServiceAsync.Util.getInstance();

    @UiField
    InputTextDate scheduleDate;
    @UiField
    InputTextDate date;
    @UiField
    InputTextAmount amount;
    @UiField
    InputTextArea comment;
    @UiField
    Button addOrUpdateAction;
    @UiField
    LabelText title;
    @UiField
    SelectList paymentMethod;
    @UiField
    LabelText invoiceNote;

    private boolean saleAmountModification;
    private Double objectFromDBAmount;
    protected boolean isInstallment;
    protected boolean isPaymentTransfer;

    public OnePaymentForm(boolean isCreation, boolean isInstallment) {
        simplePopup = true;
        setForm(binderPaymentForm, null, null);

        this.isInstallment = isInstallment;
        if (isInstallment) {
            paymentMethod.setVisible(false);
            scheduleDate.setVisible(false);
            date.setInputTitle(Messages.getLabel("payment_form_schedule_date"));
            if (isCreation) {
                title.setLabel(Messages.getLabel("payment_form_title_installment_creation"));
                addOrUpdateAction.setVisible(true);
            } else {
                title.setLabel(Messages.getLabel("payment_form_title_installment_modification"));
            }
        } else if (isCreation) {
            title.setLabel(Messages.getLabel("payment_form_title_payment_creation"));
            addOrUpdateAction.setVisible(true);
        } else {
            title.setLabel(Messages.getLabel("payment_form_title_payement_modification"));
        }
        setHandlers();
    }

    private void setHandlers() {
        addOrUpdateAction.getButton().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                validate();
            }
        });
    }

    protected void setPayment(Payment paymentFromDB) {
        this.entity = paymentFromDB;
        scheduleDate.setValue(GenericTools.getDateFromString(paymentFromDB.getScheduleDateString()));
        date.setValue(GenericTools.getDateFromString(paymentFromDB.getDateString()));
        amount.setValue(paymentFromDB.getAmount() + "");
        objectFromDBAmount = paymentFromDB.getAmount() != null ? paymentFromDB.getAmount() : 0D;
        comment.setValue(paymentFromDB.getComment());
        paymentMethod.setEnumValue(paymentFromDB.getPaymentMethod());

        //it's a payment modification
        addOrUpdateAction.setLabel("sales_modify_payment_action");
        addOrUpdateAction.setVisible(true);
    }

    protected void setInstallment(Installment installmentFromDB) {
        this.entity = installmentFromDB;
        date.setValue(GenericTools.getDateFromString(installmentFromDB.getDateString()));
        amount.setValue(installmentFromDB.getAmount() + "");
        objectFromDBAmount = installmentFromDB.getAmount() != null ? installmentFromDB.getAmount() : 0D;
        comment.setValue(installmentFromDB.getComment());

        //it's a payment modification
        addOrUpdateAction.setLabel("sales_modify_payment_action");

        if (isPaymentTransfer) {
            isInstallment = true;
            scheduleDate.setValue(GenericTools.getDateFromString(installmentFromDB.getDateString()));
            date.setValue(new Date());
            title.setLabel(Messages.getLabel("transfer_installment_to_payment_title"));
            addOrUpdateAction.setLabel("transfer_installment_to_payment_action");
            invoiceNote.setVisible(true);
        }
        addOrUpdateAction.setVisible(true);
    }

    @Override
    protected List<IField> getMandatoryFields() {
        return Arrays.asList((IField) date, amount);
    }

    @Override
    protected AbstractEntity getEntity() {
        if (isInstallment) {
            if (entity == null) {
                entity = new Installment();
                ((Installment) entity).setSale(((SalePaymentsForm) parentForm).getSale());
            }
            Installment installment = (Installment) entity;
            installment.setDateString(GenericTools.formatDateToString(date.getDateValue()));
            if (isPaymentTransfer) {
                installment.setScheduleDateString(GenericTools.formatDateToString(scheduleDate.getDateValue()));
                installment.setPaymentMethod((PaymentMethod) paymentMethod.getEnumValue());
            }
            installment.setAmount(amount.getAmountValue() == null ? 0 : amount.getAmountValue());
            installment.setComment(comment.getValue());

            return installment;
        } else {
            if (entity == null) {
                entity = new Payment();
                ((Payment) entity).setSale(((SalePaymentsForm) parentForm).getSale());
            }
            Payment payment = (Payment) entity;
            payment.setScheduleDateString(GenericTools.formatDateToString(scheduleDate.getDateValue()));
            payment.setDateString(GenericTools.formatDateToString(date.getDateValue()));
            payment.setAmount(amount.getAmountValue() == null ? 0 : amount.getAmountValue());
            payment.setComment(comment.getValue());
            payment.setPaymentMethod((PaymentMethod) paymentMethod.getEnumValue());

            return payment;
        }
    }

    @Override
    public boolean validate() {
        if (!uiValidation()) {
            return false;
        }

        if (isPaymentTransfer) {
            validateTransferToPayment();
        } else if (isInstallment) {
            validateInstallment();
        } else {
            validatePayment();
        }
        return true;
    }

    private void validateTransferToPayment() {
        final Installment installment = (Installment) serverValidation();
        if (installment == null) {
            return;
        }
        confirmSaleModification(installment.getAmount(), installment);
    }

    private void validateInstallment() {
        final Installment installment = (Installment) serverValidation();
        if (installment == null) {
            return;
        }

        saleAmountModification = installment.getId() == null;

        confirmSaleModification(installment.getAmount(), installment);
    }

    private void validatePayment() {
        final Payment payment = (Payment) serverValidation();
        if (payment == null) {
            return;
        }

        saleAmountModification = payment.getId() == null;

        confirmSaleModification(payment.getAmount(), payment);
    }

    private void successAction(boolean creation, AbstractEntity entity) {
        popup.handleClickClose();

        ListPaymentsForm listPaymentsForm = (SalePaymentsForm) parentForm;
        if (isInstallment) {
            listPaymentsForm.refreshInstallments();
        } else {
            listPaymentsForm.refreshPayments();
        }

        if (saleAmountModification) {
            if (isInstallment) {
                ((SalePaymentsForm) listPaymentsForm).refreshInstallment((Installment) entity);
            } else {
                ((SalePaymentsForm) listPaymentsForm).refreshPayment((Payment) entity);
            }
        }

        ValidationMessage validationMessageInPageContent = parentForm.messages;
        if (creation) {
            String messageKey = isInstallment ? "validation_installment_form_create_success" : "validation_payment_form_create_success";
            validationMessageInPageContent.showSuccessMessage(messageKey);
        } else {
            String messageKey = isInstallment ? "validation_installment_form_modify_success" : "validation_payment_form_modify_success";
            validationMessageInPageContent.showSuccessMessage(messageKey);
        }
    }

    private void confirmSaleModification(final Double amount, final AbstractEntity paymentOrInstallment) {
        if (paymentOrInstallment.getId() != null && !GenericTools.parseAmount(GenericTools.formatAmount(objectFromDBAmount + "")).equals(amount)) {

            ListPaymentsForm listPaymentsForm = (SalePaymentsForm) parentForm;
            if (listPaymentsForm.disableWarningMessage) {
                saleAmountModification = true;
                addOrUpdatePaymentOrInstallment(paymentOrInstallment);
                return;
            }

            String messageKey = isInstallment && !isPaymentTransfer ? "sale_installments_modification_confirm_question" : "sale_payments_modification_confirm_question";
            String titleKey = isInstallment && !isPaymentTransfer ? "sale_installments_modification_confirm_title" : "sale_payments_modification_confirm_title";

            IabakoDialogBox iabakoDialogBox = new IabakoDialogBox(titleKey, messageKey, true, "payment_add_confirm") {
                @Override
                protected void customConfirmButtonHandler() {
                    saleAmountModification = true;
                    addOrUpdatePaymentOrInstallment(paymentOrInstallment);
                }
            };
            iabakoDialogBox.setCloseOnlySimplePopup(true);

            NavigationController.getInstance().show(iabakoDialogBox);

        } else {
            addOrUpdatePaymentOrInstallment(paymentOrInstallment);
        }
    }

    private void addOrUpdatePaymentOrInstallment(AbstractEntity paymentOrInstallment) {

        final boolean creation = paymentOrInstallment.getId() == null;

        if (isPaymentTransfer) {

            saleServiceAsync.installmentToPayment((Installment) paymentOrInstallment, new IabakoAsyncCallback<Void>() {
                public void onSuccess(Void result) {
                    popup.handleClickClose();

                    ((ListPaymentsForm) parentForm).refreshInstallments();
                    ((ListPaymentsForm) parentForm).refreshPayments();
                    ((ListPaymentsForm) parentForm).customSuccessTransferAction();

                    AuthenticateUserProvider.getBalanceAccount().refresh();

                    ((ListPaymentsForm) parentForm).messages.showSuccessMessage("validation_sale_installment_to_payment_success");
                    super.onSuccess(result);
                    AuthenticateUserProvider.getNotificationPanel().refresh(NotificationType.futureInstallments, NotificationType.newPastInstallments);
                    AuthenticateUserProvider.getTrackingPanel().refresh(TrackingType.installmentToPaymentReceived);
                }
            });

        } else if (isInstallment) {
            installmentServiceAsync.save((Installment) paymentOrInstallment, new IabakoAsyncCallback<Installment>() {
                public void onSuccess(Installment result) {
                    successAction(creation, result);
                    AuthenticateUserProvider.getNotificationPanel().refresh(NotificationType.futureInstallments, NotificationType.newPastInstallments);
                    if (creation) {
                        AuthenticateUserProvider.getTrackingPanel().refresh(TrackingType.installmentNew);
                    } else {
                        AuthenticateUserProvider.getTrackingPanel().refresh(TrackingType.installmentModify);
                    }
                    super.onSuccess(result);
                }
            });
        } else {
            paymentServiceAsync.save((Payment) paymentOrInstallment, new IabakoAsyncCallback<Payment>() {
                public void onSuccess(Payment result) {
                    successAction(creation, result);
                    if (creation) {
                        AuthenticateUserProvider.getBalanceAccount().refresh();
                        AuthenticateUserProvider.getTrackingPanel().refresh(TrackingType.paymentReceivedNew);
                    } else {
                        AuthenticateUserProvider.getTrackingPanel().refresh(TrackingType.paymentReceivedModify);
                    }
                    super.onSuccess(result);
                }
            });
        }
    }
}
